// Copyright 2010 Jan Potoms. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


goog.require('extension.Module');


goog.provide('extension.reader.ClientModule');

goog.scope(function () {
  
  // import namespaces
  var Module = extension.Module;





  /** Provides basic functionality for communicating with the Google Reader service.
   * @extends {extension.Module}
   * @constructor
   * 
   * @param {extension.Context} context The context this module lives in.
   */
  extension.reader.ClientModule = function(context) {
    Module.call(this, context);
    
    this.context.registerServer('googleReaderUnreadCounts', goog.bind(this.getUnreadCounts_, this));
    
  };
  var ClientModule = extension.reader.ClientModule;
  goog.inherits(ClientModule, Module);
  
  
  
  
  
  /** Contains urls for the Reader client.
   * @type {Object}
   */
  ClientModule.URLS = {
    base: 'www.google.com/reader'  
  };
  ClientModule.URLS.APIv0 = ClientModule.URLS.base + '/api/0/'
  
  
  
  
  
  /** Wrapper for the actual XHR request.
   * @private
   * 
   * @param {string} url The url to make the request to.
   * @param {Function} onSuccess The function to be called when the request is completes successfully.
   * @param {Function} onFailure The function to be called when the request failed.
   * @param {string=} opt_method The method use for the request ('GET', 'POST').
   */
  ClientModule.prototype.sendRequest_ = function (url, onSuccess, onFailure, opt_method) {
    var xhr = new XMLHttpRequest();
  
    // Initialize timer to abort the operation when no response is returned after certain amount of time.
    var abortTimerId = window.setTimeout(function() {
      xhr.abort();
      handleError();
    }, this.context.getOption('XHRTimeout'));
  
    function handleError() {
      window.clearTimeout(abortTimerId);
      onFailure();
    }
  
    function handleSuccess(response) {
      window.clearTimeout(abortTimerId);
      onSuccess(response);
    }
    
    try {
      if (goog.DEBUG) {
        // log request: format to keep console clean 
        console.groupCollapsed('Reader: request');
        console.log(url);
        console.groupEnd();
      }
  
      xhr.onreadystatechange = function(){
        
        if (xhr.readyState === 4) {
          if (xhr.status >= 400) {
            var signedOut = xhr.status === 401;
            handleError();
          } else if (xhr.responseText) {  
            if (goog.DEBUG) {
              // log response: format to keep console clean    
              console.groupCollapsed('Reader: response');
              console.log(xhr.responseText);
              console.groupEnd();
            }
            
            handleSuccess(xhr.responseText)
          } else {
            handleError();
          }
        }
      }
  
      xhr.onerror = function(error) {
        handleError();
      }
  
      var method = opt_method || 'GET';
  
      xhr.open(method, url, true);
      xhr.send(null);
    } catch(e) {
      handleError();
    }
    
  };
  
  
  
  
   
  /** Wrapper for the actual XHR request. Returns a Json object.
   * @private
   * 
   * @param {string} url The url to make the request to.
   * @param {Function} onSuccess The function to be called when the request is completes successfully.
   * @param {Function} onFailure The function to be called when the request failed.
   * @param {string=} opt_method The method use for the request ('GET' or 'POST', defaults to 'GET').
   */
  ClientModule.prototype.sendJsonRequest_ = function (url, onSuccess, onFailure, opt_method) {
    
    function handleSuccess(response) {
      try{
        var json = JSON.parse(response);
        onSuccess(json);
      } catch(e) {
        onFailure();
      }
    }
    
    this.sendRequest_(url, handleSuccess, onFailure, opt_method);
    
  };
  
  
  
  
  
  /** Encodes an object literal to a querystring.
   * 
   * @param {Object} data The dictionary that contains the data.
   */
  ClientModule.prototype.EncodeQueryData = function (data) {
    var pairs = [];
    for (var key in data) {
      pairs.push(encodeURIComponent(key) + "=" + encodeURIComponent(data[key]));
    }
    return pairs.join("&");
  }
  
  
  
  
  
  /** Calls the list API of the Google Reader Service.
   * @private
   *
   * @param {string} apiFunction The Google Reader API function to call.
   * @param {Object} params The parameters for this request.
   * @param {Function} onSuccess The function to be called when the request is completes successfully.
   * @param {Function} onFailure The function to be called when the request failed.
   */
  ClientModule.prototype.getList_ = function (apiFunction, params, onSuccess, onFailure) {
    
    // provide values for common parameters
    params['output'] = 'json';
    params['ck'] = new Date().getTime();
    params['client'] = this.context.getOption('extensionName');
    
    var protocol = this.context.getOption('protocol');
    // Construct the url to post the request to.
    var url = protocol + ClientModule.URLS.APIv0 + apiFunction + '?' + this.EncodeQueryData(params);
    
    // Make the actual request.
    this.sendJsonRequest_(url, onSuccess, onFailure);
  
  };
  
  
  
  /** Get the tag list and shared status for each tag.
   * @protected
   * 
   * @param {*} data unused
   * @param {Function} onSuccess The function to be called when the request is completes successfully.
   * @param {Function} onFailure The function to be called when the request failed.
   */
  ClientModule.prototype.getTags_ = function (data, onSuccess, onFailure) {
  
    this.getList_('tag/list', { }, onSuccess, onFailure);
  
  };
  
  
  /** Get the subscription list and shared status for each tag.
   * @protected
   * 
   * @param {*} data unused
   * @param {Function} onSuccess The function to be called when the request is completes successfully.
   * @param {Function} onFailure The function to be called when the request failed.
   */
  ClientModule.prototype.getSubscriptions_ = function (data, onSuccess, onFailure) {
  
    this.getList_('subscription/list', { }, onSuccess, onFailure);
  
  };
  
  
  /** Get the preference list (configuration of the account for GoogleReader).
   * @protected
   * 
   * @param {*} data unused
   * @param {Function} onSuccess The function to be called when the request is completes successfully.
   * @param {Function} onFailure The function to be called when the request failed.
   */
  ClientModule.prototype.getPreferences_ = function (data, onSuccess, onFailure) {
  
    this.getList_('preference/list', { }, onSuccess, onFailure);
  
  };
  
  
  
  
  
  /** Get all the information about where the unread items are located (in term of subscriptions and tags/folders).
   * @private
   * 
   * @param {{all: boolean, tag: RegExp}} data optional parameters
   * @param {Function} onSuccess The function to be called when the request is completes successfully.
   * @param {Function} onFailure The function to be called when the request failed.
   */
  ClientModule.prototype.getUnreadCounts_ = function (data, onSuccess, onFailure) {
    
    var params = { };
    params['all'] = data.all || false;
    
    function handleSuccess(response) {
      if(!data['tag']) {
        onSuccess(response);
        return;
      }
      
      var tagMatcher = data['tag'];
      // read the unread count out of the response.
      for (var i = 0, stream; stream = response['unreadcounts'][i]; i++) {
        if (tagMatcher.test(stream['id'])) {
          onSuccess(stream['count']);
          return;
        }
      }
      
      onSuccess(0);
    }
  
    this.getList_('unread-count', params, handleSuccess, onFailure);
  
  };
  
  
  
  
  
  /** @inheritDoc */
  ClientModule.prototype.dispose = function() {
    // no eventhandlers to remove
  };
  


});